package database.dateTime;

import java.sql.Date;
import java.sql.Time;

import database.dbObjects.IDBEvent.DBEvent;

public class DBDateTime {
	
	private int day;
	private int month;
	private int year;
	
	private int hours;
	private int minutes;
	private int seconds;
	
	
	public DBDateTime() {
		
		// Default: current date and time are set
		long currentTime = System.currentTimeMillis();
		
		// Date
		Date d = new Date(currentTime - (currentTime % 86400000));
		String date = d.toString();
		day = 0;
		month = 0;
		year = 0;
		for (int i = 0; i < 4; i++) {
			year = year * 10 + date.charAt(i) - 48;
		}
		for (int i = 5; i < 7; i++) {
			month = month * 10 + date.charAt(i) - 48;
		}
		for (int i = 8; i < 10; i++) {
			day = day * 10 + date.charAt(i) - 48;
		}
		
		// Time
		String time = (new Time(currentTime)).toString();
		hours = 0;
		minutes = 0;
		seconds = 0;
		for (int i = 0; i < 2; i++) {
			hours = hours * 10 + time.charAt(i) - 48;
		}
		for (int i = 3; i < 5; i++) {
			minutes = minutes * 10 + time.charAt(i) - 48;
		}
		for (int i = 6; i < 8; i++) {
			seconds = seconds * 10 + time.charAt(i) - 48;
		}
	}
	
	public final static DBDateTime create(int day, int month, 
			int year, int hours, int min, int sec) throws Exception {
		
		DBDateTime newDateTime = new DBDateTime(day, month, year, hours, min, sec);
		newDateTime.check();
		return newDateTime;
	}
	
	public final static DBDateTime create(String dateTime) throws Exception {
		
		checkSyntax(dateTime);
		DBDateTime newDateTime = new DBDateTime(dateTime);
		newDateTime.check();
		return newDateTime;
	}
	
	public final static String getParsedString(String dateTime) throws Exception {
		checkSyntax(dateTime);
		DBDateTime dt = new DBDateTime(dateTime);
		dt.check();
		String s = dt.getDay() + "/" + dt.getMonth() + "/" + dt.getYear() + " - ";
		s += dt.getHours() + ":" + dt.getMinutes() + ":" + dt.getSeconds();
		return s;
	}
	
	public final static String decodeParsedString(String parsedString) throws Exception {
		
		String decodedString = parsedString.substring(6, 10);
		decodedString += parsedString.substring(3, 5);
		decodedString += parsedString.substring(0, 2) + "T";
		decodedString += parsedString.substring(13, 15);
		decodedString += parsedString.substring(16, 18);
		decodedString += parsedString.substring(19, 21);
		
		return decodedString;
	}
	
	public final String getDay() {
		
		String day = "";
		if (this.day < 10) {
			day += 0;
		}
		day += this.day;
		return day;
	}
	
	public final String getMonth() {
		
		String month = "";
		if (this.month < 10) {
			month += 0;
		}
		month += this.month;
		return month;
	}
	
	public final String getYear() {
		
		String year = "" + this.year;
		return year;
	}
	
	public final String getHours() {
		String hours = "";
		if (this.hours < 10) {
			hours += 0;
		}
		hours += this.hours;
		return hours;
	}
	
	public final String getMinutes() {
		String minutes = "";
		if (this.minutes < 10) {
			minutes += 0;
		}
		minutes += this.minutes;
		return minutes;
	}
	
	public final String getSeconds() {
		String seconds = "";
		if (this.seconds < 10) {
			seconds += 0;
		}
		seconds += this.seconds;
		return seconds;
	}
	
	public final static boolean inNextWeek(DBDateTime date) {
		// Determines whether 'date' is in maximum 1 week from the current date
		DBDateTime current = new DBDateTime();
		int tempDay = 0;
		int tempMonth = 0;
		if (date.beforeDate(current)){
			return false;
		} else if (date.year != current.year) {
			return false;
		} else {
			if ((current.month == 4) || (current.month == 6) || (current.month == 9) || (current.month == 11)) {
				if (current.day <= 23) {
					tempDay = current.day + 7;
					tempMonth = current.month;
				} else {
					tempDay = current.day + 7 - 30;
					tempMonth = current.month + 1;
				}
			} else if (current.month == 2) {
				if (current.day <= 21) {
					tempDay = current.day + 7;
					tempMonth = current.month;
				} else if (current.year%4 == 0) {
					tempDay = current.day + 7 - 29;
					tempMonth = current.month + 1;
				} else {
					tempDay = current.day + 7 - 28;
					tempMonth = current.month + 1;
				}
			} else {
				if (current.day <= 24) {
					tempDay = current.day + 7;
					tempMonth = current.month;
				} else {
					tempDay = current.day + 7 - 31;
					tempMonth = current.month + 1;
				}
			}
		}
		boolean success = false;
		try {
			DBDateTime week = create(tempDay, tempMonth, current.year, 0, 0, 0);
			if (date.beforeDate(week)) {
				success = true;
			}
		} catch (Exception e){
			e.printStackTrace();
		}
		
		return success;
	}
	
	public final static boolean compareDates(String d1, String d2) {
		
		if (d1.substring(0, 8).equals(d2.substring(0, 8))) {
			return true;
		}
		return false;
	}
	
	public final boolean beforeDate(DBDateTime dt) {
		if (this.year < dt.year) {
			return true;
		} else if (this.year == dt.year) {
			if (this.month < dt.month) {
				return true;
			} else if (this.month == dt.month) {
				if (this.day < dt.day) {
					return true;
				}
			}
		}
		return false;
	}
	
	public final boolean before(DBDateTime dt) {
		if (this.year < dt.year) {
			return true;
		} else if (this.year == dt.year) {
			if (this.month < dt.month) {
				return true;
			} else if (this.month == dt.month) {
				if (this.day < dt.day) {
					return true;
				} else if (this.day == dt.day) {
					if (this.hours < dt.hours) {
						return true;
					} else if (this.hours == dt.hours) {
						if (this.minutes < dt.minutes) {
							return true;
						} else if (this.minutes == dt.minutes) {
							if (this.seconds < dt.seconds) {
								return true;
							} 
						}
					}
				}
			}
		}
		return false;
	}
	
	// @ override
	public final String toString() {
		
		String s = "";
		// Date
		s += year;
		if (month < 10) {
			s += "0";
		}
		s += month;
		if (day < 10) {
			s += "0";
		}
		s += day;
		s += "T";
		
		// Time
		if (hours < 10) {
			s += "0";
		}
		s += hours;
		if (minutes < 10) {
			s += "0";
		}
		s += minutes;
		if (seconds < 10) {
			s += "0";
		}
		s += seconds;
		return s;
	}
	
	private DBDateTime(int day, int month, int year, int hours, int min, int sec) {
		
		this.day = day;
		this.month = month;
		this.year = year;
		
		this.hours = hours;
		this.minutes = min;
		this.seconds = sec;
	}
	
	private DBDateTime(String dateTime) {
		
		day = 0;
		month = 0;
		year = 0;
		hours = 0;
		minutes = 0;
		seconds = 0;
		
		for (int i = 0; i < 4; i++) {
			year = year * 10 + dateTime.charAt(i) - 48;
		}
		for (int i = 4; i < 6; i++) {
			month = month * 10 + dateTime.charAt(i) - 48;
		}
		for (int i = 6; i < 8; i++) {
			day = day * 10 + dateTime.charAt(i) - 48;
		}
		for (int i = 9; i < 11; i++) {
			hours = hours * 10 + dateTime.charAt(i) - 48;
		}
		for (int i = 11; i < 13; i++) {
			minutes = minutes * 10 + dateTime.charAt(i) - 48;
		}
		for (int i = 13; i < 15; i++) {
			seconds = seconds * 10 + dateTime.charAt(i) - 48;
		}
	}
	
	private final void check() throws Exception {
		
		// Date
		if ((day < 1) || (day > 31)) {
			throw (new Exception("DateTime: Day not between 1 and 31"));
		} else if ((month < 1) || (month > 12)) {
			throw (new Exception("DateTime: Month not between 1 and 12"));
		}
		switch (month) {
			case 2: if ( (((year % 4 == 0) && !(year % 100 == 0))
                    		|| (year % 400 == 0)) && (day > 29) ) {
						throw (new Exception("DateTime: Day exceeds " +
							"limit (29) for this month"));
					} else if (day > 28) {
						throw (new Exception("DateTime: Day exceeds " +
							"limit (28) for this month"));
					}
					break;
			case 4:
			case 6:
			case 9:
			case 11: if (day > 30) {
						throw (new Exception("DateTime: Day exceeds " +
								"limit (30) for this month"));
					 }
					 break;
			default: break;
		}
		
		// Time
		if ((hours < 0) || (hours > 23)) {
			throw (new Exception("DateTime: hours not between 0 and 23"));
		} else if ((minutes < 0) || (minutes > 59)) {
			throw (new Exception("DateTime: minutes not between 0 and 59"));
		} else if ((seconds < 0) || (seconds > 59)) {
			throw (new Exception("DateTime: seconds not between 0 and 59"));
		}
	}
	
	private final static void checkSyntax(String dateTime) throws Exception {
		
		if (dateTime.length() != DBEvent.lengthDateTimeFormat) {
			throw (new Exception("DateTime syntax error: DateTime has to be exact " +
					 DBEvent.lengthDateTimeFormat + " characters long!"));
		}
		String pattern = "(\\d{8})(T)(\\d{6})";
		// 8 characters for date, a 'T' and 6 characters for time
		if (!dateTime.matches(pattern)) {
			throw (new Exception("DateTime syntax error: wrong pattern!"));
		}
	}
	
}
